<template>
  <HeaderPage :logoQRcode="qr" />
  <!--  首页：  -->
  <!-- showFilterDialog -->
  <!-- 使用筛选弹窗 -->
  <!-- <hr color="rgb(172, 123, 56)" /> -->
  <!-- <div style="border: 1px solid rgb(172, 123, 56)"></div> -->
  <!-- <el-button type="warning" plain @click="dialogVisible = true" style="color: rgb(178, 132, 64); margin-bottom: 5px">自选</el-button> -->
  <el-button
    link
    @click="dialogVisible = true"
    style="
      color: rgb(255, 191, 36);
      padding-top: 3px;
      margin-left: 14px;
      margin-bottom: 2px;
      font-size: 0.9rem;
    "
    ><img
      src="@/assets/favicon.ico"
      alt="logo"
      width="20"
      style="line-height: 20px; margin: 0"
    />自选</el-button
  >
  <span
    style="
      float: right;
      color: red;
      padding-top: 3px;
      margin-right: 20px;
      margin-bottom: 2px;
      font-size: 0.9rem;
    "
    >{{ pubtime }} | {{ isOpen }}</span
  >

  <!--  height="500"  -->
  <el-table
    ref="table1"
    :data="filteredData"
    :row-key="getRowKey"
    :max-height="tableHeight"
    style="width: 100%"
    :header-cell-style="{
      borderTop: '1px solid rgba(119, 116, 99, 0.2)',
      borderBottom: '1px solid rgba(119, 116, 99, 0.2)'}"
    :cell-style="{borderTop: '0px solid #444', borderBottom: '1px solid rgba(119, 116, 99, 0.2)' }"
    row-class-name="tablebackcolorgray"
    >
    <!-- backgroundColor: 'rgba(48, 48, 48, 0.999)',  :row-class-name="tableRowClassName" -->
    <el-table-column class-name="namecolor" prop="name" label="商品"> </el-table-column>
    <!-- 回购和销售的标题：点击即可跳转到黄金计算页面： -->
    <el-table-column class-name="datacolor" prop="Buy" label="">
      <template #header>
        <button link @click="handleClick()" class="font-bold">回购</button>
      </template>
      <!-- 涨跌颜色控制 -->
      <template #default="scope">
        <div v-show="scope.row.name !== '美元'">
          <span
            v-show="AscendingAlgorithm(scope.row.Buy, scope.row.H, scope.row.L)"
            style="color: red"
            >{{ scope.row.Buy.toFixed(2) }}</span
          >
          <span
            v-show="!AscendingAlgorithm(scope.row.Buy, scope.row.H, scope.row.L)"
            style="color: rgb(9, 252, 50)"
            >{{ scope.row.Buy.toFixed(2) }}</span
          >
        </div>
        <div v-show="scope.row.name === '美元'">
          <span
            v-show="AscendingAlgorithm(scope.row.Buy, scope.row.H, scope.row.L)"
            style="color: red"
            >{{ scope.row.Buy }}</span
          >
          <span
            v-show="!AscendingAlgorithm(scope.row.Buy, scope.row.H, scope.row.L)"
            style="color: rgb(9, 252, 50)"
            >{{ scope.row.Buy }}</span
          >
        </div>
      </template></el-table-column>
    <el-table-column class-name="datacolor" prop="Sell" label="">
      <template #header>
        <button link @click="handleClick()" class="font-bold">销售</button>
      </template>
      <template #default="scope">
        <div v-show="scope.row.name !== '美元'">
          <span
            v-show="AscendingAlgorithm(scope.row.Buy, scope.row.H, scope.row.L)"
            style="color: red"
            >{{ scope.row.Sell.toFixed(2) }}</span
          >
          <span
            v-show="!AscendingAlgorithm(scope.row.Buy, scope.row.H, scope.row.L)"
            style="color: rgb(9, 252, 50)"
            >{{ scope.row.Sell.toFixed(2) }}</span
          >
        </div>
        <div v-show="scope.row.name === '美元'">
          <span
            v-show="AscendingAlgorithm(scope.row.Buy, scope.row.H, scope.row.L)"
            style="color: red"
            >{{ scope.row.Sell }}</span
          >
          <span
            v-show="!AscendingAlgorithm(scope.row.Buy, scope.row.H, scope.row.L)"
            style="color: rgb(9, 252, 50)"
            >{{ scope.row.Sell }}</span
          >
        </div>
      </template>
    </el-table-column>
    <el-table-column prop="MaxMni" label="高/低">
      <template #default="scope">
        <div v-show="scope.row.name !== '美元'">
          <div class="maxmin" style="color: red">
            {{ scope.row.MaxMni.H.toFixed(2) }}
          </div>
          <div class="maxmin" style="color: rgb(9, 252, 50)">
            {{ scope.row.MaxMni.L.toFixed(2) }}
          </div>
        </div>
        <div v-show="scope.row.name === '美元'">
          <div class="maxmin" style="color: red">
            {{ scope.row.MaxMni.H }}
          </div>
          <div class="maxmin" style="color: rgb(9, 252, 50)">
            {{ scope.row.MaxMni.L }}
          </div>
        </div>
      </template>
    </el-table-column>
  </el-table>

  <el-dialog v-model="dialogVisible" title="品种过滤列表" width="400" draggable>
    <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange"
      >全部</el-checkbox
    >
    <hr style="color: gray" />
    <el-checkbox-group v-model="checkedCities" @change="handleCheckedCitiesChange">
      <el-checkbox v-for="name in goldInfoList" :key="name.name" :label="name.name" :value="name.name" />
    </el-checkbox-group>
  </el-dialog>
</template>
  
<script lang="ts" setup>
import HeaderPage from '_c/HeaderPage.vue'
import { getGoldInfo, GetOpenClose} from '@/api/gold'
import type {GoldInfo, Result } from '@/api/gold'
import { ref, onMounted, onBeforeUnmount } from 'vue'
import {useFooterInfoStore} from '@/stores/modules/footerInfo';
import { ListTitle } from '@/api/footer';
import { GetPhoto } from '@/api/home';
// 获取数据列表：initFunc
const infoMap = new Map<string, string>();
const potoMap = new Map<number, string>()
const qr = ref('');
const initFunc = async () => {
  await ListTitle(1, { priceType: 0}).then((res) => {
    const lst = res.data
    // console.log('通过管理系统获取的配置信息：',res)
    for (const val of lst) {
      infoMap.set(val.name, val.description)
    }
    const store = useFooterInfoStore()
    store.change(
      '声明：'+infoMap.get('声明') as string,
      '',
      '电话：'+infoMap.get('电话') as string,
      infoMap.get('地址') as string,
      '备案：'+infoMap.get('备案') as string,
      '',
    )
  }).catch(() => {
  })
  // 图片获取：
  await GetPhoto({type:1, priceType: 0}).then((res) => {
    const lst = res.data
    for (const val of lst) {
        potoMap.set(val.type, val.content)
    }
    qr.value = potoMap.get(1) as string
    // console.log('通过管理系统获取的图片：',potoMap)
  }).catch((er) => {
    console.log('图片获取失败：',er)
  })
};
initFunc();
//
const dialogVisible = ref(false)
const tableRowClassName = ({ row, rowIndex }: { row: GoldInfo; rowIndex: number }) => {
  if (rowIndex % 2 === 0) {
    return 'tablebackcolorgray'
  } else if (rowIndex % 2 === 1) {
    // tablebackcolorblack
    return 'tablebackcolorgray'
  }
  return ''
}

</script>

<script lang="ts">
// import { io, Socket } from 'socket.io-client'
// import { useGoldInfoStore } from '@/stores/modules/goldInfo'
import { ListGoldSetting } from '@/api/gold'
import axios from 'axios';
// const store = useGoldInfoStore()
// 滚动：
const table1 = ref()

const sortName: string[] = [
  '黄金',
  '白银',
  '黄金9999',
  '黄金(T+D)',
  '白银(T+D)',
  '铂金9995',
  // '美黄金',
  // '美白银',
  // '美铂金',
  // '美钯金',
  '国际金',
  '国际银',
  '国际铂',
  '国际钯',
  '伦敦金',
  '伦敦银',
  '伦敦铂',
  '伦敦钯',
  '美元'
]
// 国际金算法添加:
var nationalAlgorithmFactor : number = 31.1034768
const name2NationalNameMap = new Map<string, string>()
name2NationalNameMap.set('伦敦金', '国际金')
name2NationalNameMap.set('伦敦银', '国际银')
name2NationalNameMap.set('伦敦铂', '国际铂')
name2NationalNameMap.set('伦敦钯', '国际钯')
// 
let sortEnglishNameMap = new Map<string, string>()
sortEnglishNameMap.set('GOLD', '黄金')
sortEnglishNameMap.set('SILVER', '白银')
sortEnglishNameMap.set('AU9999', '黄金9999')
sortEnglishNameMap.set('AUTD', '黄金(T+D)')
sortEnglishNameMap.set('AGTD', '白银(T+D)')
sortEnglishNameMap.set('TMAP9995', '铂金9995')
// sortEnglishNameMap.set('美黄金', 'SILVER')
// sortEnglishNameMap.set('美白银', 'SILVER')
// sortEnglishNameMap.set('美铂金', 'SILVER')
// sortEnglishNameMap.set('美钯金', 'SILVER')
sortEnglishNameMap.set('XAU', '伦敦金')
sortEnglishNameMap.set('XAG', '伦敦银')
sortEnglishNameMap.set('XAP', '伦敦铂')
sortEnglishNameMap.set('XPD', '伦敦钯')
sortEnglishNameMap.set('USDCNH', '美元')
// const goldInfoList = ref<GoldInfo[] | null>([])

export default {
    components: {
      HeaderPage
    },
  data() {
    return {
      // goldInfoList,
      filterDialogVisible: false,
      //   dialogVisible: true,
      filters: {} as Record<string, string>, // 添加类型注释
      goldInfoList: ref<GoldInfo[]>([] as GoldInfo[]), // 假设 goldInfoList 包含数据
      timer: null as any,
      dataTimer: null as any,
      pubtime: null as any,
      // nameList: [] as string[],
      checkAll: false,
      checkedCities: [] as string[],
      isIndeterminate: true,
      isOpen: ref(''),
      tableHeight: window.innerHeight - 175, //表格动态高度，300为页面固定头部的高度，可根据不同的页面需求更改
      screenHeight: window.innerHeight, //内容区域高度
      // socketData: data,
      buyChange: 0,
      sellChange: 0,
      isOpenByBack: ref(''),
      // socket:
      ws: null as WebSocket | null,
      heartbeatTimer: null as any, // 心跳定时器
      heartbeatInterval: 2000, // 初始心跳间隔(实际在startHeartbeat中会调整为10秒)
      reconnectTimer: null as any, // 重连定时器
      reconnectInterval: 2000, // 重连间隔(5秒)
      reconnectAttempts: 0, // 重连尝试次数
      websocketUrl: 'wss://djkx.djkx9999.com/web/v1/ws',
      // websocketUrl: 'ws://118.89.49.206:443/web/v1/ws',
      connectionTimeoutTimer: null as any,
      connectionTimeoutTimeCountMax: 10, // 这个是未连接成功的尝试此时。 连接超时最大尝试次数
      handleResize: null as any,
      socketconnStartTime: Date.now(),
    }
  },
  watch: {
    // 监听screenHeight从而改变table的高度
    screenHeight(val) {
      this.screenHeight = val
      this.tableHeight = this.screenHeight - 175
    }
  },
  mounted() {
    // window.onresize:浏览器尺寸变化响应事件
    this.handleResize = () => {
      return (() => {
        // window.innerHeight:浏览器的可用高度
        this.screenHeight = window.innerHeight
      })()
    }
    window.addEventListener('resize', this.handleResize)
  },
  created() {
    // 实现轮询
    this.getProjectList()
    // this.initWebSocket()
    this.httpData()
    this.dataTimer = setInterval(() => {
      this.httpData()
    }, 1000)
    this.timer = setInterval(() => {
      this.getOpenClose()
      // 检查内存使用情况，如果大于20MB则记录日志
      if (window.performance && (window.performance as any).memory && 
          (window.performance as any).memory.usedJSHeapSize > 20 * 1024 * 1024) {
        console.log('内存使用超过20MB:', (window.performance as any).memory.usedJSHeapSize);
      }
    }, 10000)
  },
  computed: {
    filteredData() {
      // this.nameList = []
      return this.goldInfoList.filter((item) => {
        // this.nameList.push((item as Record<string, any>)['name'])
        for (const field in this.filters) {
          // console.log('过滤：', (item as Record<string, any>)[field], field)
          if (this.filters[field] && (item as Record<string, any>)['name'] === field) {
            return false
          }
        }
        return true
      })
    }
  },
  beforeUnmount() { // 防止内存泄露。
    // 清理定时器
    if (this.timer) {
      clearInterval(this.timer)
      this.timer = null
      clearInterval(this.dataTimer)
      this.dataTimer = null
    }
    
    // // 停止WebSocket心跳和重连定时器
    // this.stopHeartbeat()
    // this.stopReconnect()
    
    // 清理数据引用
    this.goldInfoList.length = 0
    this.filters = {}
    this.checkedCities.length = 0
    
    // 关闭WebSocket连接
    if (this.ws) {
      this.ws.onopen = null
      this.ws.onmessage = null
      this.ws.onerror = null
      this.ws.onclose = null
      this.ws.close()
      this.ws = null
    }
    // 移除窗口大小调整事件监听器
    if (this.handleResize) {
      window.removeEventListener('resize', this.handleResize)
      this.handleResize = null
    }
  },
  methods: {
    getRowKey(row: any) {
      return row.name
    },
    updateFilters() {
      this.filters = {}
      this.checkedCities.forEach((item) => {
        this.filters[item] = item
      })
    },
    handleClick() {
      this.$router.push('/cacl').then(() => {
        this.$router.go(0)
      })
    },
    handleToCustPageClick() {
      this.$router.push('/customer').then(() => {
        this.$router.go(0)
      })
    },
    AscendingAlgorithm(cur: number, max: number, min: number) {
      if (cur > (max + min) / 2) {
        return true
      }
      return false
    },
    reserveFloat(x: string) {
      x = x.replace(/[^\d.]/g, '') //清除"数字"和"."以外的字符
      x = x.replace(/^\./g, '') //验证第一个字符是数字而不是
      x = x.replace(/\.{2,}/g, '.') //只保留第一个. 清除多余的
      x = x.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.')
      x = x.replace(/^(-)*(\d+)\.(\d\d).*$/, '$1$2.$3') //只能输入两个小数
      var s = x.toString().split('.')
      if (s.length == 1) {
        x = x.toString() + '.00'
        return x
      }
      if (s.length > 1) {
        if (s[1].length < 2) {
          x = x.toString() + '0'
        }
        return x
      }
      return x
    },
    showFilterDialog() {
      console.log('点击弹窗')
      console.log(this.filterDialogVisible)
      this.filterDialogVisible = true
      console.log(this.filterDialogVisible)
    },
    handleFilter(filters: Record<string, string>) {
      this.filters = filters
      this.filterDialogVisible = false
    },
    stop() {
      clearInterval(this.timer)
      this.timer = null
    },
    handleCheckAllChange(val: boolean) {
      this.filters = {}
      this.checkedCities = val ? this.goldInfoList.map((item) => item.name as string) : []
      this.isIndeterminate = false
      this.updateFilters()
    },
    handleCheckedCitiesChange(value: string[]) {
      this.filters = {}
      const checkedCount = value.length
      // this.nameList = value
      this.checkAll = checkedCount === this.goldInfoList.length
      this.isIndeterminate = checkedCount > 0 && checkedCount < this.goldInfoList.length
      this.updateFilters()
    },
    // 请求是否有新消息
    async getProjectList() {
      this.buyChange = 0
      this.sellChange = 0
      // this.nameList.length = 0
      try {
        await this.getBackGoldChange().then((ret) => {
          if (ret.Buy) {
            this.buyChange = ret.Buy
            this.sellChange = ret.Sell
          }
        })
      } catch (error) {
        console.error('getBackGoldChange 请求接口失败:', error);
      }
      // // 拦截socket
      // if (this.ws == null) {
      //   console.log('socket has closed')
      //   return
      // }
      // this.ws.onmessage = this.handlerSocketData
    }, 
    httpData() { 
      // 直接访问这个接口：
      // https://djkx.djkx9999.com/web/v1/prices/list
      // console.log('开始请求接口')
      axios.get('https://djkx.djkx9999.com/web/v1/prices/list?t=' + Date.now())
      .then((response) => {
        console.log('接口返回数据:', response.data[0])
        this.handlerSocketData(response.data[0])
      })
      .catch((error) => {
        console.error('请求失败:', error)
      })
      // const response = getGoldInfo<Result>({t: Date.now()})
      // response.then((res) => {
      //   // 直接复用socket方法。
      //   console.log('通过拦截得到的数据：', res)
      //   
      // }).catch((error) => {
      //   console.error('getGoldInfo 获取接口数据失败:', error);
      // })
    },
    handlerSocketData(event: any) {
      // 避免数组无限增长，保持合理的数据量
      if (this.goldInfoList.length > 0) {
        this.goldInfoList.splice(0, this.goldInfoList.length) // 删除前25条数据
      }
      // 遍历map：
      // const ws_data = event.data
      // console.log('通过拦截得到的数据：', ws_data)
      // test = {
      //   date: '',
      //   priceData: {}, // items
      //   status: '开盘',
      // }
      // 封装:
      // let res: Result = {
      //   pubtime: ws_data.date,
      //   items: ws_data.priceData,
      //   result: ws_data.status
      // }
      var res: Result = event
      var filterMap: Map<string, GoldInfo> = new Map<string, GoldInfo>()
      for (const [key, value] of Object.entries(res.items)) {
        if (sortEnglishNameMap.get(key) === undefined) {
          continue
        }
        var t: GoldInfo = value
        t.name = sortEnglishNameMap.get(key) as string
        filterMap.set(key, t)
      }
      res.items = filterMap
      // 国际金算法添加:
      let America:GoldInfo = res.items.get('USDCNH') as GoldInfo
      for (const [key, value] of res.items) {
        if (name2NationalNameMap.has(value.name as string)) {
          // const tmpgold: GoldInfo = 
          filterMap.set(name2NationalNameMap.get(value.name as string) as string, {
            name: name2NationalNameMap.get(value.name as string) as string,
            Buy: parseFloat(value.Buy+"") / nationalAlgorithmFactor * America.Buy,
            Sell: parseFloat(value.Sell+'') / nationalAlgorithmFactor * America.Sell,
            H: parseFloat(value.H+'') / nationalAlgorithmFactor * America.Sell,
            L: parseFloat(value.L+'') / nationalAlgorithmFactor * America.Sell,
            MaxMni: {
              H: parseFloat(value.H+'') / nationalAlgorithmFactor * America.Sell,
              L: parseFloat(value.L+'') / nationalAlgorithmFactor * America.Sell
            },
            C: name2NationalNameMap.get(value.name as string) as string
          })
        }
      }
      // console.log('清理后的数据：', res.items)
      // 黄金数据需要根据时间段控制选择不同的数据加减，其他时间段保持更改数据不变，
      // 要求如下，9:00 - 15:30  周一到周五    黄金价格在黄金9999基础上加减五毛
      // 晚上：20:00 - 2:00   周一到周五    黄金价格在黄金T+D基础上 加减五毛
      const currentTime = new Date()
      const dayOfWeek = currentTime.getDay()
      const hour = currentTime.getHours()
      const munite = currentTime.getMinutes()
      // now 是白天还是晚上：
      let nowNight = (hour >= 20 || hour + munite*0.01 < 2.30)

      const isWeekday = dayOfWeek >= 1 && dayOfWeek <= 5

      const timePeriods = {
        day: { start: 9, end: 15, endmunite: 30, baseGold: '黄金9999' },
        night: { start: 20, end: 2, endmunite: 30, baseGold: '黄金(T+D)' }
      }

      let baseGold = timePeriods.day.baseGold
      let baseChange = 0
      let buyChange = baseChange
      // let buyChange = 0.8 + 0.2 + 0.2 + 0.2
      // let sellChange = baseChange + 0.4
      let sellChange = baseChange
      // 通过后端接口获取金价最新调整：
      buyChange = buyChange + this.buyChange
      sellChange = sellChange + this.sellChange
      // 白天数据对比：
      let gold9999:GoldInfo = res.items.get('AU9999') as GoldInfo
      let goldTD:GoldInfo = res.items.get('AUTD') as GoldInfo
      // console.log('黄金9999', gold9999)
      // console.log('黄金(T+D)', goldTD)
      if (isWeekday) {
        this.isOpen = '开盘'
        if (hour >= timePeriods.night.start || hour < timePeriods.day.start) {
          baseGold = timePeriods.night.baseGold
        }
        if (
          (hour >= timePeriods.day.end &&
            munite > timePeriods.day.endmunite &&
            hour < timePeriods.night.start) ||
          (hour >= timePeriods.night.end && hour < timePeriods.day.start)) {
          this.isOpen = '闭盘'
        }
        // 这里谁的价格高，就用谁
        // td比9999的值低小于2毛，就+6毛，其他还是+5毛；然后哪个价格高就在哪个上面加。
        if (gold9999.Sell > goldTD.Sell) {
          baseGold = timePeriods.day.baseGold
          // if (gold9999.Sell - goldTD.Sell > 0.2) {
          //   baseChange = 0.6
          // }
        } else if (gold9999.Sell < goldTD.Sell) {
          baseGold = timePeriods.night.baseGold
        }
      } else {
        // 周末为晚上的数据
        baseGold = timePeriods.night.baseGold
        this.isOpen = '闭盘'
      }
      if (this.isOpenByBack !== '') {
        this.isOpen = this.isOpenByBack
      }
      // 因为销售和购买可能不一样：
      if (nowNight) { // 晚上对比td黄金
        baseGold = goldTD.name as string
      }
      const baseBuyGold:string = gold9999.name as string
      // 盘庚金
      // console.log('baseGold:', baseGold)
      let data = new Map<string, GoldInfo>()
      // 盘庚金数据添加
      for (const [, value] of res.items) {
        // 基础数据：
        if (value.name !== baseGold) {
          continue
        }
        // const pggold: GoldInfo = 
        data.set('黄金', {
          name: '黄金',
          Buy: value.Buy!=0 ? parseFloat(value.Buy+"") + buyChange : 0,
          Sell: value.Sell!=0 ? parseFloat(value.Sell+'') + sellChange : 0,
          H: parseFloat(value.H+'') + sellChange,
          L: parseFloat(value.L+'') + sellChange,
          MaxMni: {
            H: parseFloat(value.H+'') + sellChange,
            L: parseFloat(value.L+'') + sellChange
          },
          C: 'pggold'
        })
      }
      const pg: any = data.get('黄金')
      for (const [, value] of res.items) {
        if (value.name === baseBuyGold && !nowNight) { // 2024 0328 改动：回购价只在9999基础上-6毛。但是销售还是谁高用谁。
          pg.Buy = value.Buy!=0 ? parseFloat(value.Buy+"") + buyChange : 0
          break
        }
      }
      // console.log('我拿到的请求gold数据：', res.items)
      // const TableData: GoldInfo[] = []
      this.goldInfoList.push(pg)
      for (const name of sortName) {
        // for (const value of Object.values(res.items)) {
        for (const [key, value] of res.items) {
          // value.MaxMni = value.H + '/' + value.L
          if (value.name === '黄金') {
            continue
          }
          if (value.name !== name) {
            continue
          }
          value.Buy = parseFloat(value.Buy+'')
          value.Sell = parseFloat(value.Sell+'')
          value.H = parseFloat(value.H+'')
          value.L = parseFloat(value.L+'')
          value.MaxMni = {
            H: value.H,
            L: value.L
          }
          this.goldInfoList.push(value)
          // this.nameList.push(value.name as string)
        }
      }
      //
      this.pubtime = res.pubtime
    },
    // 获取金价调整。
    async getBackGoldChange() :Promise<GoldInfo> {
      let ret :GoldInfo = {} as GoldInfo
      await ListGoldSetting({ priceType: 0 }).then((res) => {
        const lst = res.data
        for (const val of lst) {
          if (val.currencyCode == 'pggold') {
            ret.Buy = val.recyclePrice / 100
            ret.Sell = val.sellPrice / 100
            break
          }
        }
        // console.log('获取金价调整：', ret)
      }).catch((err) => {
        console.error('getBackGoldChange 请求接口失败:', err);
      })
      
      return ret
    },
    // 获取开闭盘控制。
    async  getOpenClose() {
      GetOpenClose().then((res)=>{
        const now = new Date().getTime();
        let endTime: number;
        if (res.data.updateTime !== "") {
          endTime = new Date(res.data.updateTime as string).getTime() + res.data.effectHour! * 3600 * 1000
        }else {
          endTime = new Date().getTime() + res.data.effectHour! * 3600 * 1000
        }
        if (endTime - now <= 0) {
          this.isOpenByBack = ''
          return; // 不做处理
        }else {
          this.isOpenByBack = res.data.status == 1 ? '开盘' : '闭盘'
        }
        return
      }).catch(()=>{
        console.error('获取开闭盘数据失败')
      })
    },
    // socket
    // 初始化WebSocket连接
  initWebSocket() {
    try {
      // 如果已有连接，先关闭
      if (this.ws && this.ws.readyState !== WebSocket.CLOSED) {
        this.ws.close();
        this.ws = null;
      }
      
      // 添加随机参数防止浏览器缓存
      const wsUrlWithCacheBust = `${this.websocketUrl}?t=${Date.now()}`;
      this.ws = new WebSocket(wsUrlWithCacheBust);
      this.setupWebSocketEvents();
      // 等待5s钟后，判断ws已成功连接
      setTimeout(() => {
        // 5s后，判断ws时候已成功连接
        if (this.ws && this.ws.readyState !== WebSocket.OPEN) {
          if (this.reconnectAttempts >= this.connectionTimeoutTimeCountMax) {
            console.log(`超过最大尝试重连${this.connectionTimeoutTimeCountMax}次数`)
            // this.connectionTimeoutTimeCount = 0
            this.stopHeartbeat()
            this.stopReconnect()
            window.alert('数据提供商繁忙，请重新刷新尝试')
            return
          }
          this.ws.close()
          this.ws = null
          console.log('WebSocket 连接超过5s未成功建立连接，正在尝试重新连接...')
          this.reconnect()
        }
      }, 5000)
    } catch (error) {
      console.error('WebSocket连接失败:', error);
      setTimeout(() => this.reconnect(), 1000);
    }
  },
  // 清除连接超时定时器
  clearConnectionTimeout() {
    if (this.connectionTimeoutTimer) {
      clearTimeout(this.connectionTimeoutTimer);
      this.connectionTimeoutTimer = null;
    }
  },
  // 设置WebSocket事件监听
  setupWebSocketEvents() {
    if (this.ws == null) {
      return;
    }
    this.ws.onopen = (event) => {
      console.log('WebSocket连接已建立');
      const end = Date.now();
      console.log(`WebSocket连接耗时: ${end - this.socketconnStartTime}ms`);
      this.startHeartbeat();
    };

    this.ws.onmessage = (event) => {
      // 处理原有消息逻辑
      this.handlerSocketData(event);
    };

    this.ws.onerror = (event) => {
      console.error('WebSocket发生错误:', event);
      this.stopHeartbeat();
      // 错误时立即尝试重连
      setTimeout(() => this.reconnect(), 1000);
    };

    this.ws.onclose = (event) => {
      console.log('WebSocket连接已关闭:', event);
      this.stopHeartbeat();
      // 根据关闭码判断是否需要重连
      if (event.code !== 1000) { // 1000表示正常关闭
        setTimeout(() => this.reconnect(), 1000);
      }
    };
  },

  // 开始心跳检测
  startHeartbeat() {
    this.stopHeartbeat(); // 先清除之前的心跳定时器
    // 增加心跳间隔到10秒，减少不必要的网络请求
    this.heartbeatInterval = 10000;
    this.heartbeatTimer = setInterval(() => {
      if (this.ws && this.ws.readyState === WebSocket.OPEN) {
        // 发送心跳消息，可以根据后端要求调整格式
        try {
          this.ws.send(JSON.stringify({ type: 'ping' }));
        } catch (error) {
          console.error('发送心跳包失败:', error);
          this.stopHeartbeat();
          this.reconnect();
        }
      }
    }, this.heartbeatInterval);
  },

  // 重置心跳（收到消息时调用）
  resetHeartbeat() {
    this.stopHeartbeat();
    this.startHeartbeat();
  },

  // 停止心跳检测
  stopHeartbeat() {
    if (this.heartbeatTimer) {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = null;
    }
  },

  // 重连机制 - 增加指数退避策略
  reconnect() {
    this.stopReconnect(); // 清除之前的重连定时器
    
    // 实现指数退避策略，避免频繁重连导致的性能问题
    this.reconnectAttempts = this.reconnectAttempts || 0;
    this.reconnectAttempts++;
    
    // 最大重连间隔为30秒
    const maxReconnectInterval = 10000;
    // 基础重连间隔为5秒，每次重连增加1.5倍
    const currentReconnectInterval = Math.min(
      this.reconnectInterval * Math.pow(1.5, this.reconnectAttempts - 1),
      maxReconnectInterval
    );
    
    this.reconnectTimer = setTimeout(() => {
      console.log(`尝试重新连接WebSocket (第${this.reconnectAttempts}次尝试)...`);
      this.initWebSocket();
    }, currentReconnectInterval);
  },

  // 停止重连
  stopReconnect() {
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
      // 重置重连尝试次数
      // this.reconnectAttempts = 0;
    }
  }
  }
}
</script>


  <style>
  /*table header */
th {
  border-right: 0.5px solid #444 !important;
  font-size: 1.4rem !important;
  height: 70px;
  text-align: center !important;
  color: #fff !important;
  /* 强调 */
  /* background-color: rgb(37, 37, 37)!important; */
  background-color: rgba(48, 48, 48, 0.999) !important ;
  /* box-shadow: 0px 0px 0px 0.5px #444 !important; */
}
td {
  border-right: 0.4px solid rgba(119, 116, 99, 0.2) !important;
  /* box-shadow: 0px 0px 0px 0.5px #444 !important; */
}
th>div.cell {
  font-family: '微软雅黑' !important;
  text-align: center !important;
  color: #fff !important;
  /* 强调 */
  /* background-color: black !important; */
  font-weight: 700 !important;
}
div.cell {
  overflow:visible !important;
  padding: 0 0 !important;
}
td>div.cell {
  font-size: 1.1rem;
  font-weight: 500;
  /* height: 40px; 导致不能居中 */
  text-align: center;
  vertical-align:middle !important;
}
.el-table .warning-row {
  --el-table-tr-bg-color: var(--el-color-warning-light-9);
}
.el-table .success-row {
  --el-table-tr-bg-color: var(--el-color-success-light-9);
}
/* @media (min-width: 1024px) {
  .about {
    min-height: 100vh;
    display: flex;
    align-items: center;
  }
} */
</style>